#!/usr/bin/env python3
# Utility to generate Recover Message for Corvette Bootloader assisted Wired updates

import argparse
import sys
from Crypto.Cipher import AES
import array
import hashlib
import hmac
import os
import binascii
import importlib

from am_defines import *
#from keys_info import recoveryKey

#******************************************************************************
#
# Generate the image blob as per command line parameters
#
#******************************************************************************
def process(binfile, n0, n1, n2, n3, custId, output, keyFile):

    if (binfile != ''):
        # Read the binary file from the command line.
        with open(binfile, mode='rb') as binfile:
            blob = binfile.read()
        # Gather the important binary metadata.
        blobLen = len(blob)
    else:
        blob = bytearray()
        blobLen = 0

    filenames = keyFile.split('.')
    keys = importlib.import_module(filenames[0])

    # Send Recover command
    print('Building Recover Command.')

    hdr_binarray = bytearray([0x00]*(AM_WU_RECOVERY_HDR_SIZE)) 
    fill_word(hdr_binarray, 4, (((blobLen + AM_WU_RECOVERY_HDR_SIZE) << 16) | AM_SECBOOT_WIRED_MSGTYPE_RECOVER))
    # CustId
    fill_word(hdr_binarray, AM_WU_RECOVERY_HDR_OFFSET_CUSTID, custId)
    # Recovery key
    for x in range(0, AM_SECBOOT_AESCBC_BLOCK_SIZE_BYTES):
        hdr_binarray[AM_WU_RECOVERY_HDR_OFFSET_RECKEY + x]  = keys.recoveryKey[x]
    # Nonce
    fill_word(hdr_binarray, AM_WU_RECOVERY_HDR_OFFSET_NONCE + 0, n0)
    fill_word(hdr_binarray, AM_WU_RECOVERY_HDR_OFFSET_NONCE + 4, n1)
    fill_word(hdr_binarray, AM_WU_RECOVERY_HDR_OFFSET_NONCE + 8, n2)
    fill_word(hdr_binarray, AM_WU_RECOVERY_HDR_OFFSET_NONCE + 12, n3)

    # Compute crc
    crc = crc32(hdr_binarray[4:AM_WU_RECOVERY_HDR_SIZE] + blob)
    fill_word(hdr_binarray, 0, crc)

    # Write the message as a raw message
    with open(output + '.msg', mode = 'wb') as out:
        print("Writing to file ", output + '.msg')
        out.write(hdr_binarray + blob)

def parse_arguments():
    parser = argparse.ArgumentParser(description =
                     'Generate Corvette Recovery Message')

    parser.add_argument('-f', dest='binfile', default='',
                        help = 'Binary file representing the raw Recovery Blob provided by Ambiq')

    parser.add_argument('-o', dest = 'output',
                        help = 'Output filename (without the extension)')

    parser.add_argument('--n0', dest = 'n0', type=auto_int, default=0xFFFFFFFF,
                        help = 'Nonce 0 - should correspond to the value provided to Ambiq (default = 0xFFFFFFFF)')

    parser.add_argument('--n1', dest = 'n1', type=auto_int, default=0xFFFFFFFF,
                        help = 'Nonce 1 - should correspond to the value provided to Ambiq (default = 0xFFFFFFFF)')

    parser.add_argument('--n2', dest = 'n2', type=auto_int, default=0xFFFFFFFF,
                        help = 'Nonce 2 - should correspond to the value provided to Ambiq (default = 0xFFFFFFFF)')

    parser.add_argument('--n3', dest = 'n3', type=auto_int, default=0xFFFFFFFF,
                        help = 'Nonce 3 - should correspond to the value provided to Ambiq (default = 0xFFFFFFFF)')

    parser.add_argument('--custId', dest='custId', type=auto_int, default=0xFFFFFFFF,
                        help='Customer ID - should correspond to the value provided to Ambiq (default = 0xFFFFFFFF)')
 
    parser.add_argument('-k', type=str, dest='keyFile', nargs='?', default='keys_info.py',
                        help='key file in specified format [default = keys_info.py]')

    args = parser.parse_args()

    return args

#******************************************************************************
#
# Main function.
#
#******************************************************************************
def main():
    # Read the arguments.
    args = parse_arguments()


    process(args.binfile, args.n0, args.n1, args.n2, args.n3, args.custId, args.output, args.keyFile)

if __name__ == '__main__':
    main()
